package com.logisticsrepair.controller;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.extra.mail.Mail;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.api.R;
import com.logisticsrepair.config.ThreadPoolTaskConfig;
import com.logisticsrepair.entity.*;
import com.logisticsrepair.enums.OrderProcessEnum;
import com.logisticsrepair.enums.RepairStatusEnum;
import com.logisticsrepair.service.*;
import com.logisticsrepair.util.RedisUtil;
import com.logisticsrepair.util.mail.MailService;
import com.logisticsrepair.util.responseUtil.ResponseEnum;
import com.logisticsrepair.util.responseUtil.ResponseUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.bind.annotation.*;
import redis.clients.jedis.Jedis;

import java.util.*;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;


@RestController
@RequestMapping("/workerHome")
@Slf4j
public class WorkerHomeController {

    Jedis redis = RedisUtil.getRedis();

    @Autowired
    private RepairOrdersService repairOrdersService;

    @Autowired
    private OrderProcessService orderProcessService;

    @Autowired
    private MaterialLibraryService materialLibraryService;

    @Autowired
    private ApplyMaterialService applyMaterialService;

    @Autowired
    private ThreadPoolTaskConfig threadPoolTaskConfig;

    @Autowired
    private WorkerService workerService;

    @Autowired
    private MailService mailService;

    @PostMapping("/codeCheck")
    public ResponseUtil workerRegCodeCheck(@RequestBody Map<String, String> code) {
        if (redis.exists(LoginController.ADD_WORKER_PREFIX + code.get("value"))) {
            return ResponseUtil.setE(ResponseEnum.OK).setMsg("受邀成功");
        }
        return ResponseUtil.setE(ResponseEnum.FAIL).setMsg("无效邀请码");
    }

    @GetMapping("/queryNewOrders")
    public ResponseUtil queryNewOrders() {
        return ResponseUtil.setE(ResponseEnum.OK).setData(repairOrdersService.queryNewOrders());
    }

    @PostMapping("/acceptOrder")
    public ResponseUtil acceptOrder(@RequestBody RepairOrdersEntity entity) {
        entity.setWorkerOpenid(StpUtil.getLoginId().toString());
        //entity.setUserOpenid(StpUtil.getLoginId().toString());//维修员的openid
        int result = repairOrdersService.acceptOrder(entity.getRepairVersion(),
                entity.getWorkerOpenid(),
                entity.getOrderId());
        switch (result) {
            case 1:
                return ResponseUtil.setE(ResponseEnum.OK).setMsg("接单成功");
            case 0:
                return ResponseUtil.setE(ResponseEnum.FAIL).setMsg("接单失败");
            case -1:
            default:
                return ResponseUtil.setE(ResponseEnum.FAIL).setMsg("接单错误");
        }
    }

    @PostMapping("/queryWorkerOrder")
    public ResponseUtil queryWorkerOrder(@RequestBody(required = false) Map<String, Object> condition) {
        String workerOpenid = StpUtil.getLoginId().toString();
        condition.put("workerOpenid", workerOpenid);

        List<RepairOrdersEntity> repairOrdersEntities = repairOrdersService.queryWorkerOrder(condition);

        List<Map<String, Object>> orderIdAndStatusCodeList = new ArrayList<>();

        repairOrdersEntities.forEach(item -> {
            HashMap<String, Object> orderIdAndStatusCode = new HashMap<>();
            orderIdAndStatusCode.put("orderId", item.getOrderId());
            orderIdAndStatusCode.put("statusCode", item.getStatusCode().getStatusCode());
            orderIdAndStatusCodeList.add(orderIdAndStatusCode);

            /**
             * 脱敏处理
             */
            if (
                    item.getStatusCode().equals(RepairStatusEnum.REJECTED) ||
                            item.getStatusCode().equals(RepairStatusEnum.HAVE_FINISHED)
            ) {
                item.setRepairPhone(DesensitizedUtil.mobilePhone(item.getRepairPhone()));
                item.setRepairAddress(DesensitizedUtil.address(item.getRepairAddress(), item.getRepairAddress().length() / 2));
                UserEntity userEntity = new UserEntity();
                userEntity.setNickname(DesensitizedUtil.chineseName(item.getUserEntity().getNickname()));
                item.setUserEntity(userEntity);
            }
        });
        List<OrderProcessEntity> orderProcessEntities = queryOrderDetailsStep(orderIdAndStatusCodeList);
        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("repairOrdersEntities", repairOrdersEntities);
        resultMap.put("orderProcessEntities", orderProcessEntities);
        return ResponseUtil.setE(ResponseEnum.OK).setData(resultMap);
    }

    private List<OrderProcessEntity> queryOrderDetailsStep(List<Map<String, Object>> list) {
        List<OrderProcessEntity> orderHandlerStep = new ArrayList<>();
        List<String> otherOrder = new ArrayList<>();

        //if (map.isEmpty()) return ResponseUtil.setE(ResponseEnum.FAIL).setMsg("订单信息为不能空");
        for (Map<String, Object> map : list) {
            String order = map.get("orderId").toString();
            int statusCode = (int) map.get("statusCode");
            /**
             * 只有statusCode为[2待受理, 5待完结]状态的订单，缓存在redis中，其它状态的订单都保存在mysql中
             */
            if (statusCode == RepairStatusEnum.HAVE_ACCEPTED.getStatusCode() ||
                    statusCode == RepairStatusEnum.WAIT_FINISHED.getStatusCode()) {
                String res = redis.get(order);
                if (StrUtil.isEmpty(res)) {
                    OrderProcessEntity orderProcessEntity = new OrderProcessEntity();
                    orderProcessEntity.setOrderId(order);
                    orderProcessEntity.setContactConfirmation(OrderProcessEnum.process.name());

                    redis.setnx(order, JSON.toJSONString(orderProcessEntity));
                    orderHandlerStep.add(orderProcessEntity);
                    continue;
                }
                orderHandlerStep.add(JSONObject.parseObject(res, OrderProcessEntity.class));
                continue;
            }
            /**
             * 其它状态的订单
             */
            otherOrder.add(order);
        }

        if (!otherOrder.isEmpty()) {
            List<OrderProcessEntity> entityList = orderProcessService.listByIds(otherOrder);
            orderHandlerStep.addAll(entityList);
        }

        return orderHandlerStep;
    }

    @PostMapping("/confirmContact")
    public ResponseUtil confirmContact(@RequestBody Map<String, Object> map) {
        String order = map.get("order").toString();
        if (map.isEmpty()) return ResponseUtil.setE(ResponseEnum.FAIL).setMsg("订单信息不能为空");

        OrderProcessEntity byId = orderProcessService.getById(order);
        if (byId != null) return ResponseUtil.setE(ResponseEnum.FAIL).setMsg("订单信息有误");

        OrderProcessEntity orderProcessEntity = new OrderProcessEntity();
        orderProcessEntity.setOrderId(order);
        orderProcessEntity.setContactConfirmation(OrderProcessEnum.success.name());
        orderProcessEntity.setApplyMaterial(OrderProcessEnum.process.name());

        redis.set(order, JSON.toJSONString(orderProcessEntity));
        return ResponseUtil.setE(ResponseEnum.OK).setData(orderProcessEntity).setMsg("联系确认成功");
    }


    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/rejectOrder")
    public ResponseUtil rejectOrder(@RequestBody RepairOrdersEntity repairOrdersEntity) {
        if (!repairOrdersService.rejectOrder(repairOrdersEntity))
            return ResponseUtil.setE(ResponseEnum.FAIL).setMsg("订单驳回失败1");

        OrderProcessEntity orderProcessEntity = new OrderProcessEntity();
        orderProcessEntity.setOrderId(repairOrdersEntity.getOrderId());
        orderProcessEntity.setContactConfirmation(OrderProcessEnum.error.name());

        boolean save = orderProcessService.save(orderProcessEntity);
        if (!save) return ResponseUtil.setE(ResponseEnum.FAIL).setMsg("订单驳回失败2");
        redis.del(repairOrdersEntity.getOrderId());
        return ResponseUtil.setE(ResponseEnum.OK).setData(orderProcessEntity).setMsg("订单驳回成功");
    }

    @GetMapping("/getMaterialLibrary")
    public ResponseUtil getMaterialLibrary() {
        List<MaterialLibraryEntity> list = materialLibraryService.list();
        int size = list.size();
        for (int i = 0; i < size; i++) {
            if (list.get(i).getMaterialAmount().intValue() <= 0){
                list.remove(i);
                i--;
                size--;
            }
        }
        return ResponseUtil.setE(ResponseEnum.OK).setData(list);
    }

    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/submitApply")
    public ResponseUtil submitApply(@RequestBody Map<String, Object> map) {
        List<MaterialLibraryEntity> applyData = JSONArray.parseArray(map.get("applyData").toString(), MaterialLibraryEntity.class);

        String hashCode = map.get("hashCode").toString();

        String md5Hex = DigestUtil.md5Hex(map.get("applyData").toString());

        String orderId = map.get("orderId").toString();

        if (!md5Hex.equals(hashCode) || applyData.isEmpty())
            return ResponseUtil.setE(ResponseEnum.FAIL).setMsg("订单信息有误");

        LambdaQueryWrapper<ApplyMaterialEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(ApplyMaterialEntity::getOrderId, orderId);
        List<ApplyMaterialEntity> list = applyMaterialService.list(lambdaQueryWrapper);

        if (!list.isEmpty()) return ResponseUtil.setE(ResponseEnum.FAIL).setMsg("订单信息有误");
        /**
         * 1、减库存
         */
        for (MaterialLibraryEntity entity : applyData) {
            MaterialLibraryEntity materialLibraryEntity = (MaterialLibraryEntity) entity.clone();
            materialLibraryEntity.setMaterialName(null);
            materialLibraryEntity.setMaterialPrice(null);
            materialLibraryEntity.setMaterialAmount(materialLibraryEntity.getMaterialAmount() - materialLibraryEntity.getTakeAmount());
            boolean updateRes = materialLibraryService.updateById(materialLibraryEntity);
            if (!updateRes) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return ResponseUtil.setE(ResponseEnum.FAIL).setMsg("申请材料失败，请重试。");
            }
        }

        /**
         * 2、存订单
         */
        DateTime applyTime = DateUtil.date();
        ArrayList<ApplyMaterialEntity> applyMaterialEntities = new ArrayList<>();
        for (MaterialLibraryEntity entity : applyData) {
            ApplyMaterialEntity applyMaterialEntity = new ApplyMaterialEntity();
            applyMaterialEntity.setOrderId(orderId);
            applyMaterialEntity.setMaterialId(entity.getMaterialId());
            applyMaterialEntity.setMaterialPrice(entity.getMaterialPrice());
            applyMaterialEntity.setTakeAmount(entity.getTakeAmount());
            applyMaterialEntity.setApplyTime(applyTime);
            applyMaterialEntities.add(applyMaterialEntity);
        }
        applyMaterialService.saveBatch(applyMaterialEntities);

        /**
         * 3、更新步骤
         */
        OrderProcessEntity orderProcessEntity = new OrderProcessEntity();
        orderProcessEntity.setOrderId(orderId);
        orderProcessEntity.setContactConfirmation(OrderProcessEnum.success.name());
        orderProcessEntity.setApplyMaterial(OrderProcessEnum.success.name());
        orderProcessEntity.setChargeOn(OrderProcessEnum.process.name());

        redis.set(orderId, JSON.toJSONString(orderProcessEntity));

        ThreadPoolExecutor threadPoolExecutor = threadPoolTaskConfig.threadPoolExecutor();
        threadPoolExecutor.execute(() -> {
            WorkerEntity workerEntity = workerService.queryWorkerEmailInRepairOrdersByWorkerOpenid(orderId);
            String voucher = RandomUtil.randomNumbers(6);
            HashMap<String, Object> data = new HashMap<>();
            data.put("orderId", orderId);
            data.put("applyTime", applyTime);
            data.put("voucher", voucher);
            data.put("workerName", workerEntity.getWorkerName());
            redis.set("voucher:" + voucher, JSON.toJSONString(data));
            mailService.sendHtmlTemplateMail(workerEntity.getWorkerEmail(), "材料申报凭证", data, "EmailTemplate");
        });

        return ResponseUtil.setE(ResponseEnum.OK).setMsg("材料申报成功").setData(orderProcessEntity);
    }

    @PostMapping("/noApply")
    public ResponseUtil noApply(@RequestBody Map<String, Object> map) {
        String order = map.get("order").toString();
        if (map.isEmpty()) return ResponseUtil.setE(ResponseEnum.FAIL).setMsg("订单信息不能为空");

        OrderProcessEntity orderProcessEntity = new OrderProcessEntity();
        orderProcessEntity.setOrderId(order);
        orderProcessEntity.setContactConfirmation(OrderProcessEnum.success.name());
        orderProcessEntity.setApplyMaterial(OrderProcessEnum.error.name());
        orderProcessEntity.setChargeOn(OrderProcessEnum.error.name());
        orderProcessEntity.setOrderCompleted(OrderProcessEnum.process.name());

        redis.set(order, JSON.toJSONString(orderProcessEntity));
        return ResponseUtil.setE(ResponseEnum.OK).setData(orderProcessEntity).setMsg("未申报材料，收费项自动关闭");
    }

    @PostMapping("/getOrderMaterialInfo")
    public ResponseUtil getOrderMaterialInfo(@RequestBody Map<String, Object> map) {
        String orderId = map.get("orderId").toString();
        List<ApplyMaterialEntity> applyMaterialEntities = applyMaterialService.queryOrderMaterialInfo(orderId);
        return ResponseUtil.setE(ResponseEnum.OK).setData(applyMaterialEntities).setMsg("材料订单查询成功");
    }

    @Transactional
    @PostMapping("/submitChargeItem")
    public ResponseUtil submitChargeItem(@RequestBody List<ApplyMaterialEntity> list) {
        if (list.isEmpty()) return ResponseUtil.setE(ResponseEnum.FAIL).setMsg("订单信息错误");

        ArrayList<ApplyMaterialEntity> entities = new ArrayList<>();
        for (ApplyMaterialEntity applyMaterialEntity : list) {
            ApplyMaterialEntity entity = new ApplyMaterialEntity();
            entity.setApplyId(applyMaterialEntity.getApplyId());
            entity.setChargeOn(true);
            entities.add(entity);
        }
        boolean batchById = applyMaterialService.updateBatchById(entities);
        if (!batchById) return ResponseUtil.setE(ResponseEnum.FAIL).setMsg("收费项开启失败");

        String openid = StpUtil.getLoginId().toString();

        LambdaUpdateWrapper<RepairOrdersEntity> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(RepairOrdersEntity::getOrderId, list.get(0).getOrderId())
                .eq(RepairOrdersEntity::getWorkerOpenid, openid)
                .set(RepairOrdersEntity::getStatusCode, RepairStatusEnum.WAIT_FINISHED);

        repairOrdersService.update(lambdaUpdateWrapper);

        OrderProcessEntity orderProcessEntity = new OrderProcessEntity();
        orderProcessEntity.setOrderId(list.get(0).getOrderId());
        orderProcessEntity.setContactConfirmation(OrderProcessEnum.success.name());
        orderProcessEntity.setApplyMaterial(OrderProcessEnum.success.name());
        orderProcessEntity.setChargeOn(OrderProcessEnum.success.name());
        orderProcessEntity.setOrderCompleted(OrderProcessEnum.process.name());
        redis.set(list.get(0).getOrderId(), JSON.toJSONString(orderProcessEntity));

        return ResponseUtil.setE(ResponseEnum.OK).setMsg("收费项开启成功").setData(orderProcessEntity);
    }

    @GetMapping("/noChargeItem")
    public ResponseUtil noChargeItem(@RequestParam String orderId) {
        if (StrUtil.isEmpty(orderId)) return ResponseUtil.setE(ResponseEnum.FAIL).setMsg("订单信息错误");
        OrderProcessEntity orderProcessEntity = new OrderProcessEntity();
        orderProcessEntity.setOrderId(orderId);
        orderProcessEntity.setContactConfirmation(OrderProcessEnum.success.name());
        orderProcessEntity.setApplyMaterial(OrderProcessEnum.success.name());
        orderProcessEntity.setChargeOn(OrderProcessEnum.error.name());
        orderProcessEntity.setOrderCompleted(OrderProcessEnum.process.name());
        redis.set(orderId, JSON.toJSONString(orderProcessEntity));
        return ResponseUtil.setE(ResponseEnum.OK).setMsg("无需收费").setData(orderProcessEntity);
    }

    @GetMapping("/queryOrderCompletedInfo")
    public ResponseUtil queryOrderCompletedInfo(@RequestParam String orderId) {
        if (StrUtil.isEmpty(orderId)) return ResponseUtil.setE(ResponseEnum.FAIL).setMsg("订单信息错误");
        List<ApplyMaterialEntity> list = applyMaterialService.queryOrderMaterialInfo(orderId);
        return ResponseUtil.setE(ResponseEnum.OK).setData(list);
    }

    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/completedOrderIsNotApplyMaterial")
    public ResponseUtil completedOrderIsNotApplyMaterial(@RequestBody RepairOrdersEntity entity){

        RepairOrdersEntity repairOrdersEntity = new RepairOrdersEntity();
        repairOrdersEntity.setOrderId(entity.getOrderId());
        repairOrdersEntity.setStatusCode(RepairStatusEnum.HAVE_FINISHED);
        repairOrdersEntity.setRepairComplateDate(new Date());
        repairOrdersService.updateById(repairOrdersEntity);

        OrderProcessEntity orderProcessEntity = JSONObject.parseObject(redis.get(entity.getOrderId()), OrderProcessEntity.class);
        orderProcessEntity.setOrderCompleted(OrderProcessEnum.success.name());
        orderProcessService.save(orderProcessEntity);
        redis.del(entity.getOrderId());

        return ResponseUtil.setE(ResponseEnum.OK).setMsg("订单已完结").setData(orderProcessEntity);
    }

    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/completedOrder")
    public ResponseUtil completedOrder(@RequestBody List<ApplyMaterialEntity> applyMaterialEntities) {
        if (applyMaterialEntities.isEmpty())  return ResponseUtil.setE(ResponseEnum.FAIL).setMsg("订单信息不能为空");

        /**
         * 完结材料申报订单信息
         */
            ArrayList<ApplyMaterialEntity> entityArrayList = new ArrayList<>();
            for (ApplyMaterialEntity entity : applyMaterialEntities) {
                ApplyMaterialEntity applyMaterialEntity = new ApplyMaterialEntity();
                applyMaterialEntity.setApplyId(entity.getApplyId());
                if (!entity.getChargeOn()) applyMaterialEntity.setChargeTime(new Date());
                applyMaterialEntity.setApplyStatus(true);
                entityArrayList.add(applyMaterialEntity);
            }
            applyMaterialService.updateBatchById(entityArrayList);


        /**
         * 完结申报订单信息
         */
        String orderId = applyMaterialEntities.get(0).getOrderId();
        LambdaUpdateWrapper<RepairOrdersEntity> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(RepairOrdersEntity::getOrderId, orderId)
                .eq(RepairOrdersEntity::getWorkerOpenid, StpUtil.getLoginId().toString())
                .set(RepairOrdersEntity::getStatusCode, RepairStatusEnum.HAVE_FINISHED)
                .set(RepairOrdersEntity::getRepairComplateDate, DateUtil.date());
        repairOrdersService.update(lambdaUpdateWrapper);


        /**
         * 录入订单状态处理信息
         */
        OrderProcessEntity orderProcessEntity = JSONObject.parseObject(redis.get(orderId), OrderProcessEntity.class);
        orderProcessEntity.setOrderCompleted(OrderProcessEnum.success.name());
        orderProcessService.save(orderProcessEntity);
        redis.del(orderId);

        return ResponseUtil.setE(ResponseEnum.OK).setMsg("订单已完结").setData(orderProcessEntity);
    }
}
